package com.ice.base.util;

import com.ice.base.constant.HCNetSDK;
import com.ice.base.dao.SysLoginDao;
import com.ice.body.hardware.model.DeviceFace;
import com.sun.jna.Pointer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.*;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.HashMap;

/**
 * 获取和下发人脸信息工具类
 */
@Component
public class GetFaceUtil {
    
    private Logger logger = LoggerFactory.getLogger(GetFaceUtil.class);

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    private SysLoginDao dao;

    /**
     * 获取人脸信息
     */
    public void getFaceFuc(String cardNo , DeviceFace faceModel){
        int iErr = 0;
        HCNetSDK.NET_DVR_DEVICEINFO m_strDeviceInfo= new HCNetSDK.NET_DVR_DEVICEINFO();
        // 初始化SDK
//        HCNetSDK.INSTANCE.NET_DVR_Init();

        // 用户注册
        int lUserID = HCNetSDK.INSTANCE.NET_DVR_Login(faceModel.getIp(),(short)Integer.parseInt(faceModel.getPort()),faceModel.getUserName(),faceModel.getPwd(),m_strDeviceInfo);

        // 确定登录状态
        if(lUserID == -1 ){
            System.out.println("登录失败");
            int error= HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            System.out.println("错误代码"+error);
            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            return;
        }

        HCNetSDK.NET_DVR_FACE_PARAM_COND m_struFaceInputParam = new HCNetSDK.NET_DVR_FACE_PARAM_COND();

        m_struFaceInputParam.dwSize = m_struFaceInputParam.size();
        m_struFaceInputParam.byCardNo = cardNo.getBytes(); //人脸关联的卡号
        m_struFaceInputParam.byEnableCardReader[0]  = 1;
        m_struFaceInputParam.dwFaceNum = 1;
        m_struFaceInputParam.byFaceID = 1;
        m_struFaceInputParam.write();

        Pointer lpInBuffer = m_struFaceInputParam.getPointer();
        Pointer pUserData = null;
        FRemoteCfgCallBackFaceGet  fRemoteCfgCallBackFaceGet = new FRemoteCfgCallBackFaceGet();

        int lHandle = HCNetSDK.INSTANCE.NET_DVR_StartRemoteConfig(lUserID, HCNetSDK.NET_DVR_GET_FACE_PARAM_CFG, lpInBuffer, m_struFaceInputParam.size(),fRemoteCfgCallBackFaceGet, pUserData);
        if (lHandle < 0){
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logger.info("建立长连接失败，错误号：" + iErr);
            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            return;
        }
        logger.info("建立获取卡参数长连接成功!");

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if(!HCNetSDK.INSTANCE.NET_DVR_StopRemoteConfig(lHandle))
        {
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logger.info("断开长连接失败，错误号：" + iErr);
        }
//        HCNetSDK.INSTANCE.NET_DVR_Cleanup();
        HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
        logger.info("断开长连接成功!");

    }

    /**
     * @Title FRemoteCfgCallBackFaceGet
     * @Package ClientDemo
     * @Description 获取人脸信息回调
     * @author pang
     * @date 2019年8月23日
     * @version v1.0
     */
    public class FRemoteCfgCallBackFaceGet implements HCNetSDK.FRemoteConfigCallback{
        public void invoke(int dwType, Pointer lpBuffer, int dwBufLen, Pointer pUserData){
            System.out.println("长连接回调获取数据,NET_SDK_CALLBACK_TYPE_STATUS:" + dwType);
            switch (dwType){
                case 0:// NET_SDK_CALLBACK_TYPE_STATUS
                    HCNetSDK.REMOTECONFIGSTATUS_CARD struCfgStatus  = new HCNetSDK.REMOTECONFIGSTATUS_CARD();
                    struCfgStatus.write();
                    Pointer pCfgStatus = struCfgStatus.getPointer();
                    pCfgStatus.write(0, lpBuffer.getByteArray(0, struCfgStatus.size()), 0,struCfgStatus.size());
                    struCfgStatus.read();

                    int iStatus = 0;
                    for(int i=0;i<4;i++){
                        int ioffset = i*8;
                        int iByte = struCfgStatus.byStatus[i]&0xff;
                        iStatus = iStatus + (iByte << ioffset);
                    }

                    switch (iStatus){
                        case 1000:// NET_SDK_CALLBACK_STATUS_SUCCESS
                            System.out.println("查询人脸参数成功,dwStatus:" + iStatus);
                            break;
                        case 1001:
                            System.out.println("正在查询人脸参数中,dwStatus:" + iStatus);
                            break;
                        case 1002:
                            int iErrorCode = 0;
                            for(int i=0;i<4;i++){
                                int ioffset = i*8;
                                int iByte = struCfgStatus.byErrorCode[i]&0xff;
                                iErrorCode = iErrorCode + (iByte << ioffset);
                            }
                            System.out.println("查询人脸参数失败, dwStatus:" + iStatus + "错误号:" + iErrorCode);
                            break;
                    }
                    break;
                case 2: //NET_SDK_CALLBACK_TYPE_DATA
                    HCNetSDK.NET_DVR_FACE_PARAM_CFG m_struFaceInfo = new HCNetSDK.NET_DVR_FACE_PARAM_CFG();
                    m_struFaceInfo.write();
                    Pointer pInfoV30 = m_struFaceInfo.getPointer();
                    pInfoV30.write(0, lpBuffer.getByteArray(0, m_struFaceInfo.size()), 0,m_struFaceInfo.size());
                    m_struFaceInfo.read();
                    String cardNo = new String(m_struFaceInfo.byCardNo).trim();
                    System.out.println("查询到人脸数据关联的卡号,getCardNo:" + cardNo + ",人脸数据类型:" + m_struFaceInfo.byFaceDataType);
                    if(m_struFaceInfo.dwFaceLen >0){
                        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
                        String newName = cardNo+".jpg";
                        FileOutputStream fout;
                        String filePath = BaseUtil.getVideoPath()+"faceImg\\"+newName;

                        String facePath = newName+".jpg";
                        HashMap<String,Object> param = new HashMap<>();
                        param.put("facePath",facePath);
                        param.put("cardNo",cardNo);
                        dao.updateFacePathByCardNo(param);
                        try {
                            fout = new FileOutputStream(filePath);
                            //将字节写入文件
                            long offset = 0;
                            ByteBuffer buffers = m_struFaceInfo.pFaceBuffer.getByteBuffer(offset, m_struFaceInfo.dwFaceLen);
                            byte [] bytes = new byte[m_struFaceInfo.dwFaceLen];
                            buffers.rewind();
                            buffers.get(bytes);
                            fout.write(bytes);
                            fout.close();

                          //  SysLoginModel user = dao.selectUserByCardNo(str);
                            setFaceClose(newName,filePath);// 下发人脸信息给关门人脸识别设备
                            //setFaceCabinet(str,filePath);// 下发人脸信息给试剂柜人脸识别设备
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    }
    /**
     * 下发人脸信息给关门人脸识别设备
     * @param cardNo
     * @param filePath
     */
    public void setFaceOpen(String cardNo,String filePath) {

        HCNetSDK.NET_DVR_DEVICEINFO m_strDeviceInfo= new HCNetSDK.NET_DVR_DEVICEINFO();

        // 初始化SDK
//        HCNetSDK.INSTANCE.NET_DVR_Init();

        // 用户注册
        int lUserID = HCNetSDK.INSTANCE.NET_DVR_Login("192.168.100.115",(short)Integer.parseInt("8000"),"admin","a1234567",m_strDeviceInfo);

        // 确定登录状态
        if(lUserID  == -1){
            int error= HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            System.out.println("登录失败,错误代码"+error);
            return;
        }

        int iErr = 0;

        //设置人脸参数
        HCNetSDK.NET_DVR_FACE_PARAM_COND m_struFaceSetParam = new HCNetSDK.NET_DVR_FACE_PARAM_COND();
        m_struFaceSetParam.dwSize = m_struFaceSetParam.size();
        m_struFaceSetParam.byCardNo = cardNo.getBytes(); //人脸关联的卡号
        m_struFaceSetParam.byEnableCardReader[0]  = 1;
        m_struFaceSetParam.dwFaceNum = 1;
        m_struFaceSetParam.byFaceID = 1;
        m_struFaceSetParam.write();

        Pointer lpInBuffer = m_struFaceSetParam.getPointer();

        Pointer pUserData = null;
        FRemoteCfgCallBackFaceSet fRemoteCfgCallBackFaceSet = new FRemoteCfgCallBackFaceSet();

        int lHandle = HCNetSDK.INSTANCE.NET_DVR_StartRemoteConfig(lUserID, HCNetSDK.NET_DVR_SET_FACE_PARAM_CFG, lpInBuffer, m_struFaceSetParam.size(), fRemoteCfgCallBackFaceSet, pUserData);

        if (lHandle < 0){
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logger.info("建立长连接失败，错误号：" + iErr);

            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            return;
        }
        logger.info("建立设置卡参数长连接成功!");

        HCNetSDK.NET_DVR_FACE_PARAM_CFG struFaceInfo = new HCNetSDK.NET_DVR_FACE_PARAM_CFG(); //卡参数
        struFaceInfo.read();
        struFaceInfo.dwSize = struFaceInfo.size();
        struFaceInfo.byCardNo = cardNo.getBytes();
        struFaceInfo.byEnableCardReader[0] = 1; //需要下发人脸的读卡器，按数组表示，每位数组表示一个读卡器，数组取值：0-不下发该读卡器，1-下发到该读卡器
        struFaceInfo.byFaceID = 1; //人脸ID编号，有效取值范围：1~2
        struFaceInfo.byFaceDataType  = 1; //人脸数据类型：0- 模板（默认），1- 图片

        /*****************************************
         * 从本地文件里面读取JPEG图片二进制数据
         *****************************************/
        FileInputStream picfile = null;
        int picdataLength = 0;
        try{
            picfile = new FileInputStream(new File(filePath));
        }
        catch(FileNotFoundException e)
        {
            e.printStackTrace();
        }

        try{
            picdataLength = picfile.available();
        }
        catch(IOException e1)
        {
            e1.printStackTrace();
        }
        if(picdataLength < 0)
        {
            System.out.println("input file dataSize < 0");
            return;
        }

        HCNetSDK.BYTE_ARRAY ptrpicByte = new HCNetSDK.BYTE_ARRAY(picdataLength);
        try {
            picfile.read(ptrpicByte.byValue);
        } catch (IOException e2) {
            e2.printStackTrace();
        }
        ptrpicByte.write();
        /**************************/

        struFaceInfo.dwFaceLen  = picdataLength;
        struFaceInfo.pFaceBuffer  = ptrpicByte.getPointer();

        struFaceInfo.write();
        Pointer pSendBufSet = struFaceInfo.getPointer();

        //ENUM_ACS_INTELLIGENT_IDENTITY_DATA = 9,  //智能身份识别终端数据类型，下发人脸图片数据
        if(!HCNetSDK.INSTANCE.NET_DVR_SendRemoteConfig(lHandle, 0x9, pSendBufSet, struFaceInfo.size()))
        {
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logger.info("NET_DVR_SendRemoteConfig失败，错误号：" + iErr);
            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            return;
        }

//        try {
//            Thread.sleep(2000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        if(!HCNetSDK.INSTANCE.NET_DVR_StopRemoteConfig(lHandle))
        {
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            logger.info("断开长连接失败，错误号：" + iErr);
        }
//        if(HCNetSDK.INSTANCE.NET_DVR_Cleanup()) {
//            logger.info("SDK释放成功");
//        }
        if(HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID)){
            logger.info("logOut登出成功");
        }
        logger.info("断开长连接成功!");
    }
    /**
     * 下发人脸信息给关门人脸识别设备
     * @param cardNo
     * @param filePath
     */
    public void setFaceClose(String cardNo,String filePath) {

        HCNetSDK.NET_DVR_DEVICEINFO m_strDeviceInfo= new HCNetSDK.NET_DVR_DEVICEINFO();
        // 初始化SDK
//        HCNetSDK.INSTANCE.NET_DVR_Init();
        // 用户注册
        int lUserID = HCNetSDK.INSTANCE.NET_DVR_Login("192.168.100.155",(short)Integer.parseInt("8000"),"admin","a1234567",m_strDeviceInfo);

        // 确定登录状态
        if(lUserID == -1){
            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            System.out.println("登录失败 ,错误代码"+HCNetSDK.INSTANCE.NET_DVR_GetLastError());
            return;
        }

        int iErr = 0;

        //设置人脸参数
        HCNetSDK.NET_DVR_FACE_PARAM_COND m_struFaceSetParam = new HCNetSDK.NET_DVR_FACE_PARAM_COND();
        m_struFaceSetParam.dwSize = m_struFaceSetParam.size();
        m_struFaceSetParam.byCardNo = cardNo.getBytes(); //人脸关联的卡号
        m_struFaceSetParam.byEnableCardReader[0]  = 1;
        m_struFaceSetParam.dwFaceNum = 1;
        m_struFaceSetParam.byFaceID = 1;
        m_struFaceSetParam.write();

        Pointer lpInBuffer = m_struFaceSetParam.getPointer();

        Pointer pUserData = null;
        FRemoteCfgCallBackFaceSet fRemoteCfgCallBackFaceSet = new FRemoteCfgCallBackFaceSet();

        int lHandle = HCNetSDK.INSTANCE.NET_DVR_StartRemoteConfig(lUserID, HCNetSDK.NET_DVR_SET_FACE_PARAM_CFG, lpInBuffer, m_struFaceSetParam.size(), fRemoteCfgCallBackFaceSet, pUserData);

        if (lHandle< 0){
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logger.info("建立长连接失败，错误号：" + iErr);
            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            return;
        }
        logger.info("下发人脸-建立设置卡参数长连接成功!");

        HCNetSDK.NET_DVR_FACE_PARAM_CFG struFaceInfo = new HCNetSDK.NET_DVR_FACE_PARAM_CFG(); //卡参数
        struFaceInfo.read();
        struFaceInfo.dwSize = struFaceInfo.size();
        struFaceInfo.byCardNo = cardNo.getBytes();
        struFaceInfo.byEnableCardReader[0] = 1; //需要下发人脸的读卡器，按数组表示，每位数组表示一个读卡器，数组取值：0-不下发该读卡器，1-下发到该读卡器
        struFaceInfo.byFaceID = 1; //人脸ID编号，有效取值范围：1~2
        struFaceInfo.byFaceDataType  = 1; //人脸数据类型：0- 模板（默认），1- 图片

        /*****************************************
         * 从本地文件里面读取JPEG图片二进制数据
         *****************************************/
        FileInputStream picfile = null;
        int picdataLength = 0;
        try{
            picfile = new FileInputStream(new File(filePath));
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }

        try{
            picdataLength = picfile.available();
        }catch(IOException e1){
            e1.printStackTrace();
        }
        if(picdataLength < 0){
            System.out.println("input file dataSize < 0");
            return;
        }

        HCNetSDK.BYTE_ARRAY ptrpicByte = new HCNetSDK.BYTE_ARRAY(picdataLength);
        try {
            picfile.read(ptrpicByte.byValue);
        } catch (IOException e2) {
            e2.printStackTrace();
        }
        ptrpicByte.write();
        /**************************/

        struFaceInfo.dwFaceLen  = picdataLength;
        struFaceInfo.pFaceBuffer  = ptrpicByte.getPointer();

        struFaceInfo.write();
        Pointer pSendBufSet = struFaceInfo.getPointer();

        //ENUM_ACS_INTELLIGENT_IDENTITY_DATA = 9,  //智能身份识别终端数据类型，下发人脸图片数据
        if(!HCNetSDK.INSTANCE.NET_DVR_SendRemoteConfig(lHandle, 0x9, pSendBufSet, struFaceInfo.size())){
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logger.info("NET_DVR_SendRemoteConfig失败，错误号：" + iErr);
            HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
            return;
        }

        if(!HCNetSDK.INSTANCE.NET_DVR_StopRemoteConfig(lHandle)){
            iErr = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logger.info("断开长连接失败，错误号：" + iErr);
        }
//        if(HCNetSDK.INSTANCE.NET_DVR_Cleanup()) {
//            logger.info("SDK释放成功");
//        }
        if(HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID)){
            logger.info("下发人脸-logOut登出成功");
        }
        logger.info("断开长连接成功!");
    }

    /**
     * @Title FRemoteCfgCallBackFaceSet
     * @Package ClientDemo
     * @Description 下发人脸信息回调
     * @author pang
     * @date 2019年8月23日
     * @version v1.0
     */
    public class FRemoteCfgCallBackFaceSet implements HCNetSDK.FRemoteConfigCallback
    {
        public void invoke(int dwType, Pointer lpBuffer, int dwBufLen, Pointer pUserData)
        {
            System.out.println("长连接回调获取数据,NET_SDK_CALLBACK_TYPE_STATUS:" + dwType);
            switch (dwType){
                case 0:// NET_SDK_CALLBACK_TYPE_STATUS
                    HCNetSDK.REMOTECONFIGSTATUS_CARD struCfgStatus  = new HCNetSDK.REMOTECONFIGSTATUS_CARD();
                    struCfgStatus.write();
                    Pointer pCfgStatus = struCfgStatus.getPointer();
                    pCfgStatus.write(0, lpBuffer.getByteArray(0, struCfgStatus.size()), 0,struCfgStatus.size());
                    struCfgStatus.read();

                    int iStatus = 0;
                    for(int i=0;i<4;i++){
                        int ioffset = i*8;
                        int iByte = struCfgStatus.byStatus[i]&0xff;
                        iStatus = iStatus + (iByte << ioffset);
                    }

                    switch (iStatus){
                        case 1000:// NET_SDK_CALLBACK_STATUS_SUCCESS
                            System.out.println("下发人脸参数成功,dwStatus:" + iStatus);
                            break;
                        case 1001:
                            System.out.println("正在下发人脸参数中,dwStatus:" + iStatus);
                            break;
                        case 1002:
                            int iErrorCode = 0;
                            for(int i=0;i<4;i++){
                                int ioffset = i*8;
                                int iByte = struCfgStatus.byErrorCode[i]&0xff;
                                iErrorCode = iErrorCode + (iByte << ioffset);
                            }
                            System.out.println("下发人脸参数失败, dwStatus:" + iStatus + "错误号:" + iErrorCode);
                            System.out.println("下发人脸参数失败, dwStatus:" + iStatus + "错误号:" + HCNetSDK.INSTANCE.NET_DVR_GetLastError());
                            break;
                    }
                    break;
                case 2:// 获取状态数据
                    HCNetSDK.NET_DVR_FACE_PARAM_STATUS  m_struFaceStatus = new HCNetSDK.NET_DVR_FACE_PARAM_STATUS();
                    m_struFaceStatus.write();
                    Pointer pStatusInfo = m_struFaceStatus.getPointer();
                    pStatusInfo.write(0, lpBuffer.getByteArray(0, m_struFaceStatus.size()), 0,m_struFaceStatus.size());
                    m_struFaceStatus.read();
                    String str = new String(m_struFaceStatus.byCardNo).trim();
                    System.out.println("下发人脸数据关联的卡号:" + str + ",人脸读卡器状态:" +
                            m_struFaceStatus.byCardReaderRecvStatus[0] + ",错误描述:" + new String(m_struFaceStatus.byErrorMsg).trim());
                default:
                    break;
            }
        }
    }
    
}